﻿// //  ********************************************************************************
// //  Copyright (C) 2016 Sebastian Kenter. All rights reserved.
// // 
// //  Name    : PhotonServerProject | MasterServer | RegisterSubServerRequestHandler.cs
// //  Created : 2016 - 04 - 04 14:28
// //  Modified: 2016 - 04 - 18 09:38
// //  ********************************************************************************

using System;
using ExitGames.Logging;
using NHibernate;
using PhotonServerCommon;
using PhotonServerCommon.Entities.Domain;
using PhotonServerCommon.Enums;
using PhotonServerCommon.Messages;
using PhotonServerCommon.Messages.Helper;
using PhotonServerFramework.Implementation.Database;
using PhotonServerFramework.Implementation.Server;
using PhotonServerFramework.Implementation.Telegram;
using PhotonServerFramework.Interfaces.Handler;
using PhotonServerFramework.Interfaces.Server;
using PhotonServerFramework.Interfaces.Telegram;

namespace MasterServer.Handler.Request
{
    public class RegisterSubServerRequestHandler : IServerTelegramHandler<IServerPeer>
    {
        public ILogger Logger { get; }
        public Guid HandlerId { get; set; } = Guid.NewGuid();
        public HandlerTypes HandlerType => HandlerTypes.Request;
        public byte HandlerCode => (byte) OperationCodes.System;
        public int HandlerSubCode => (int) OperationSubCodes.RegisterSubServer;

        public RegisterSubServerRequestHandler(ILogger logger)
        {
            Logger = logger;
        }

        public bool HandleTelegram(ITelegram telegram, IServerPeer serverPeer)
        {
            bool handled = false;

            Logger.InfoFormat("Trying to handle telegram of type={0} with code={1}, subcode={2}", telegram.Type,
                (OperationCodes) telegram.TelegramCode, (OperationSubCodes) telegram.TelegramSubCode);

            ServerPeer tempServerPeer = serverPeer as ServerPeer;

            if (tempServerPeer == null) return false;

            RegisterSubServerRequest message =
                MessageSerializer.DeserializeMessage<RegisterSubServerRequest>(
                    (byte[]) telegram.TelegramParameters[(byte) ParameterCodes.RegisterSubServerRequestMessage]);

            if (message != null)
            {
                ServerPeerT localServerPeer = null;
                ServerPeerT remoteServerPeer = null;

                using (ISession session = SessionManager.OpenSession())
                {
                    // Lookin up the peer where the local peer id equals to the peer id in the register request 
                    // (that's here the remote peer!)
                    using (ITransaction transaction = session.BeginTransaction())
                    {
                        try
                        {
                            remoteServerPeer =
                                session.QueryOver<ServerPeerT>()
                                    .Where(s => s.LocalPeerId == message.ServerPeerId)
                                    .SingleOrDefault<ServerPeerT>();
                            transaction.Commit();
                        }
                        catch (Exception ex)
                        {
                            Logger.ErrorFormat("Operation failed with: {0}", ex.Message);
                            transaction.Rollback();
                        }
                    }
                    // Looking up the peer where the local peer id equals the server peer id of the requesting server peer 
                    // (that's here the local peer!)
                    using (ITransaction transaction = session.BeginTransaction())
                    {
                        try
                        {
                            localServerPeer =
                                session.QueryOver<ServerPeerT>()
                                    .Where(s => s.LocalPeerId == serverPeer.ServerPeerId.ToString())
                                    .SingleOrDefault<ServerPeerT>();
                            transaction.Commit();
                        }
                        catch (Exception ex)
                        {
                            Logger.ErrorFormat("Operation failed with: {0}", ex.Message);
                            transaction.Rollback();
                        }
                    }

                    if (localServerPeer != null && remoteServerPeer != null)
                    {
                        Logger.InfoFormat("Server peer set found (local = {0} - remote = {1}) - updating local peer.",
                            localServerPeer.LocalPeerId, remoteServerPeer.LocalPeerId);

                        using (ITransaction transaction = session.BeginTransaction())
                        {
                            try
                            {
                                localServerPeer.Connected = 1;
                                localServerPeer.RemoteIp = remoteServerPeer.LocalIp;
                                localServerPeer.RemotePort = remoteServerPeer.LocalPort;
                                localServerPeer.RemoteServerId = remoteServerPeer.LocalServerId;
                                localServerPeer.RemoteServerType = remoteServerPeer.LocalServerType;
                                localServerPeer.RemotePeerId = message.ServerPeerId;
                                localServerPeer.DzUpd = DateTime.Now;
                                localServerPeer.NamUpd = GetType().Name;
                                localServerPeer.Tsn += 1;
                                session.Update(localServerPeer);
                                transaction.Commit();
                            }
                            catch (Exception ex)
                            {
                                Logger.ErrorFormat("Operation failed with: {0}", ex.Message);
                                transaction.Rollback();
                            }
                        }

                        Logger.InfoFormat("Sending response to requesting server.");

                        RegisterSubServerResponse response = new RegisterSubServerResponse
                                                             {
                                                                 ServerPeerId =
                                                                     tempServerPeer
                                                                     .ServerPeerId
                                                                     .ToString()
                                                             };

                        telegram.TelegramParameters.Add((byte) ParameterCodes.RegisterSubServerResponseMessage,
                            MessageSerializer.SerializeMessage(response));

                        tempServerPeer.SendTelegram(new ResponseTelegram
                                                    {
                                                        TelegramCode = telegram.TelegramCode,
                                                        TelegramSubCode = telegram.TelegramSubCode,
                                                        TelegramParameters = telegram.TelegramParameters,
                                                        DebugMessage = EnumHelper.GetEnumDescription(ErrorCodes.Ok),
                                                        ReturnCode = (short) ErrorCodes.Ok
                                                    });
                        handled = true;
                    }

                    session.Close();
                }
            }

            return handled;
        }
    }
}
